home *** CD-ROM | disk | FTP | other *** search
/ SGI Freeware 1998 June / SGI Freeware 1998 June.iso / dist / fw_UMINNgopher.idb / usr / freeware / src / gopher_1.12 / gopher / CURcurses.c.z / CURcurses.c
C/C++ Source or Header  |  1997-09-09  |  21KB  |  1,031 lines

  1. /********************************************************************
  2.  * $Author: drich $
  3.  * $Revision: 1.1 $
  4.  * $Date: 1995/10/03 04:07:54 $
  5.  * $Source: /proj/freeware1.0/gopher1.12/src/gopher/RCS/CURcurses.c,v $
  6.  * $State: Exp $
  7.  *
  8.  * Paul Lindner, University of Minnesota CIS.
  9.  *
  10.  * Copyright 1991, 1992 by the Regents of the University of Minnesota
  11.  * see the file "Copyright" in the distribution for conditions of use.
  12.  *********************************************************************
  13.  * MODULE: CURcurses.c
  14.  * Abstraction of all Curses Functions
  15.  *********************************************************************
  16.  * Revision History:
  17.  * $Log: CURcurses.c,v $
  18.  * Revision 1.1  1995/10/03  04:07:54  drich
  19.  * gopher 1.2 check-in
  20.  *
  21.  * Revision 1.8  1993/01/11  20:25:31  lindner
  22.  * Fixed weird wprintw error on EP/IX.
  23.  *
  24.  * Revision 1.7  1993/01/09  02:16:21  lindner
  25.  * Changed (void*)-1 constructs to SIG_ERR
  26.  *
  27.  * Revision 1.6  1993/01/09  01:28:11  lindner
  28.  * Replaced hosed Log messages (Ooops!)
  29.  *
  30.  * Revision 1.5  1993/01/09  01:24:42  lindner
  31.  * Added CURchoice(), let's you choose one option from [2-9] items.
  32.  *
  33.  * Revision 1.4  1993/01/09  00:49:16  lindner
  34.  * More mods for VMS from jqj.  Looks like better ctrl-y and ctrl-c
  35.  * processing.
  36.  *
  37.  * Revision 1.3  1993/01/06  17:05:46  lindner
  38.  * Added nl() to CURexit() for EP/IX machines.
  39.  *
  40.  * Revision 1.2  1992/12/31  05:55:44  lindner
  41.  * Mods for VMS
  42.  *
  43.  * Revision 1.1  1992/12/10  06:16:51  lindner
  44.  * Initial revision
  45.  *
  46.  *
  47.  *********************************************************************/
  48.  
  49. #include "CURcurses.h"
  50. #include "Malloc.h"
  51. #include <signal.h>
  52. #include "Stdlib.h"
  53. #include "compatible.h"
  54.  
  55. #ifdef VMS
  56. void setterm_pas();
  57. void resetterm();
  58. static int w_getch();
  59. #define wgetch w_getch
  60. #endif
  61.  
  62.  
  63. /*
  64.  * Initialize data space for various screen information
  65.  */
  66.  
  67. CursesObj *
  68. CURnew()
  69. {
  70.      CursesObj *cur;
  71.  
  72.      cur = (CursesObj *) malloc(sizeof(CursesObj));
  73.  
  74.      cur->Screen       = NULL;
  75.      cur->Termtype     = STRnew();
  76.      cur->Clearscreen  = STRnew();
  77.      cur->AudibleBell  = STRnew();
  78.      cur->Highlighton  = STRnew();
  79.      cur->Highlightoff = STRnew();
  80.  
  81.      cur->inCurses     = FALSE;
  82.      cur->sigtstp      = (void*)-1;
  83.      cur->sigwinch     = (void*)-1;
  84.  
  85.      CURinit(cur);
  86.      
  87.      return(cur);
  88.  
  89. }
  90.  
  91.  
  92. /*
  93.  * Initialize various strings and such. 
  94.  */
  95.  
  96. void
  97. CURinit(cur)
  98.   CursesObj *cur;
  99. {
  100.      int err;
  101.      static char terminal[1024];
  102.      static char capabilities[1024];   /* String for cursor motion */
  103.      static char *ptr = capabilities;  /* for buffering         */
  104.      char *cp;
  105.  
  106.  
  107. #ifdef VMS
  108.      CURsetTerm(cur, "VMS");
  109.      CURsetBell(cur, "\007");
  110.      CURsetCLS(cur, "");
  111.      CURsetHighon(cur, "");
  112.      CURsetHighoff(cur, "");
  113. #else
  114.      /*** Set the terminal type ***/
  115.      if (getenv("TERM") != NULL)
  116.       CURsetTerm(cur, getenv("TERM"));
  117.      else 
  118.       CURsetTerm(cur, "unknown");
  119.  
  120.      err = tgetent(terminal, CURgetTerm(cur));
  121.      
  122.      if (err !=1)
  123.       CURsetTerm(cur, "unknown");
  124.  
  125.      /*** Get the clearscreen code ***/
  126.      if ((cp = (char *)tgetstr("cl", &ptr)) != NULL)
  127.       CURsetCLS(cur, cp);
  128.      else
  129.       CURsetCLS(cur, "");
  130.  
  131.      /*** Set the bell ***/
  132.      if ((cp = (char *) tgetstr("bl", &ptr)) != NULL)
  133.       CURsetBell(cur, cp);
  134.      else
  135.       CURsetBell(cur, "\007");
  136.  
  137.      /*** Set the highlight codes ***/
  138.      if ((cp = (char *) tgetstr("so", &ptr)) != NULL) {
  139.       CURsetHighon(cur, cp);
  140.       if ((cp = (char *) tgetstr("se", &ptr)) != NULL)
  141.            CURsetHighoff(cur, cp);
  142.      } else {
  143.       CURsetHighon(cur, "");
  144.       CURsetHighoff(cur, "");
  145.      }
  146.      CURsetScreen(cur,initscr());
  147. #endif
  148.      cur->inCurses = FALSE;
  149.      
  150. }
  151.  
  152.  
  153. /* 
  154.  * Given a properly "CURnew" cursesobj, initialize the screen..
  155.  */
  156.  
  157. void
  158. CURenter(cur)
  159.   CursesObj *cur;
  160. {
  161.      /* for safety */
  162.      if (cur->inCurses == TRUE)
  163.       return;
  164.  
  165. #ifdef VMS
  166.      (void)setterm_pas();
  167.      CURsetScreen(cur,initscr());
  168. #else
  169.      tputs(CURgetCLS(cur),1,CURoutchar);
  170.      fflush(stdout); 
  171. #endif
  172.  
  173.      cur->inCurses = TRUE;
  174.  
  175.      CURwenter(cur,stdscr);
  176.  
  177. #ifdef SIGWINCH
  178.      if (cur->sigwinch != SIG_ERR)
  179.       signal(SIGWINCH, cur->sigwinch);
  180. #endif
  181. #ifndef VMS
  182.      if (cur->sigtstp != SIG_ERR)
  183.       signal(SIGTSTP, cur->sigtstp);
  184. #endif
  185. }
  186.  
  187. /*
  188.  * Set up processing for the window (especially for system V curses!
  189.  */
  190.  
  191. void
  192. CURwenter(cur, win)
  193.   CursesObj *cur;
  194.   WINDOW *win;
  195. {
  196.      cbreak();
  197.      noecho();
  198.      nonl();
  199. #ifdef SYSVCURSES
  200.      intrflush(win, FALSE);
  201.      nodelay(win, FALSE);
  202. #ifndef ultrix            /** Causes wgetch to dump core in ultrix **/
  203.      keypad(win, TRUE);
  204. #endif
  205. #endif
  206. }     
  207. /*
  208.  * Exit curses system.
  209.  */
  210.  
  211. void
  212. CURexit(cur)
  213.   CursesObj *cur;
  214. {
  215.      
  216.      if (!cur->inCurses)
  217.     return;
  218.      cur->inCurses = FALSE;
  219.      echo();
  220.      nl();
  221.      endwin();
  222.  
  223. #ifdef SYSVCURSES
  224.      keypad(stdscr, FALSE);
  225. #endif
  226.  
  227. #ifdef VMS
  228.      (void)resetterm();
  229. #else
  230.      tputs(CURgetCLS(cur),1,CURoutchar);
  231.      fflush(stdout);
  232.  
  233.      cur->sigtstp = signal(SIGTSTP, SIG_DFL);
  234. #endif
  235.  
  236. #ifdef SIGWINCH
  237.      cur->sigwinch = signal(SIGWINCH, SIG_DFL);
  238. #endif
  239.  
  240. }
  241.  
  242.  
  243.  
  244. /*
  245.  * send a character to stdout, not really curses, but we do use it...
  246.  */
  247.  
  248. int
  249. CURoutchar(c)
  250.   char c;
  251. {
  252.      /** output the given character.  From tputs... **/
  253.      /** Note: this CANNOT be a macro!              **/
  254.      
  255.      putc(c, stdout);
  256.      return(c);
  257. }
  258.  
  259.  
  260. /*
  261.  * Centerline, uses curses routines to center a line.
  262.  */
  263. void CURcenterline(cur, theline, yval)
  264.   CursesObj *cur;
  265.   char      *theline;
  266.   int       yval;
  267. {
  268.      mvaddstr(yval, (COLS - strlen(theline))/2, theline);
  269. }
  270.  
  271.  
  272. /*
  273.  * CURwgetstr is a replacement of getstr that allows editing of the string
  274.  *
  275.  * if the user types control codes we don't recognize, it's returned instead
  276.  *
  277.  * We assume that the incoming string is shorter than the max..
  278.  *
  279.  */
  280.  
  281.  
  282. int
  283. CURwgetstr(cur, win, inputline, maxlength)
  284.   CursesObj *cur;
  285.   WINDOW    *win;
  286.   char      *inputline;
  287.   int       maxlength;
  288. {
  289.      int pointer = 0;
  290.      int curpointer = 0;
  291.      int ch;
  292.      int y,x;
  293.  
  294.      CURwenter(cur, win);
  295.      cbreak();
  296.      noecho();
  297.  
  298.      wstandout(win);
  299.  
  300.      /*** Check to see if there's something in the inputline already ***/
  301.      
  302.      while (inputline[pointer] != '\0') {
  303.       waddch(win, inputline[pointer]);
  304.       pointer ++;
  305.       curpointer ++;
  306.      }
  307.  
  308.      wrefresh(win);
  309.  
  310.      for (;;) {
  311.       ch = CURwgetch(cur,win);
  312.  
  313.       switch (ch) {
  314.  
  315.       case '\n':
  316.            inputline[pointer] = '\0';
  317.            return(ch);
  318.            break;
  319.  
  320.       /**  Backspace and delete **/
  321.  
  322.       case '\b':
  323.            if (curpointer > 0) {
  324.             char *cp;
  325.  
  326.             getyx(win, y,x);
  327.             wmove(win, y, x-1);
  328.             
  329.             /** Update the string **/
  330.  
  331.             for (cp = inputline +curpointer-1; *cp != '\0'; cp++) {
  332.              *cp = *(cp+1);
  333.              if (*cp != '\0') waddch(win, *cp);
  334.             }
  335.             *cp = '\0';
  336.             waddch(win, ' ');
  337.             waddch(win, ' ');
  338.  
  339.             pointer--;
  340.             curpointer--;
  341.  
  342.             wmove(win, y, x-1);
  343.            
  344.             wrefresh(win);
  345.            } else
  346.             CURBeep(cur);
  347.            break;
  348.  
  349.       case '\007':  /*** ^G cancel... ***/
  350.            CURBeep(cur);
  351.            wstandend(win);
  352.            return(-1);
  353.            break;
  354.            
  355.       /*** Kill character (ctrl-u) ***/
  356.       case '\025':
  357.            while (pointer!=0) {
  358.             waddch(win,'\010');
  359.             waddch(win, ' ');
  360.             waddch(win, '\010');
  361.            
  362.             inputline[--pointer] = '\0';
  363.             curpointer = 0;
  364.            }
  365.            wrefresh(win);
  366.            break;
  367.  
  368.       case KEY_LEFT:
  369.            if (curpointer > 0) {
  370.  
  371.             curpointer--;
  372.             getyx(win, y, x);
  373.             wmove(win, y, x-1);
  374.             wrefresh(win);
  375.            }
  376.            break;
  377.  
  378.       case KEY_RIGHT:
  379.            if (curpointer<pointer) {
  380.             int y,x;
  381.  
  382.             curpointer++;
  383.             getyx(win, y, x);
  384.             wmove(win, y, x+1);
  385.             wrefresh(win);
  386.            }
  387.            break;
  388.  
  389.       default:
  390.            if (isprint(ch) && curpointer == maxlength) {
  391.             CURBeep(cur);
  392.            }
  393.            else if (isprint(ch)) {
  394.  
  395.             inputline[curpointer++] = ch;
  396.  
  397.             if (curpointer > pointer) {
  398.              pointer = curpointer;
  399.              inputline[curpointer+1] = '\0';
  400.             }
  401.             waddch(win, ch);
  402.             wrefresh(win);
  403.            }
  404.            else {
  405.             wstandend(win);
  406.             return(ch);
  407.            }
  408.       }
  409.      }
  410. }
  411.  
  412.  
  413. /*
  414.  * This stuff is stolen and modified from hytelnet  Thanks Earl!
  415.  */
  416.  
  417. int
  418. CURwgetch(cur, window)
  419.   CursesObj *cur;
  420.   WINDOW *window;
  421. {
  422.      int a, b, c;
  423.      
  424.      c = wgetch(window);
  425.      
  426.      if (c == 27) {      /* handle escape sequence */
  427.       b = wgetch(window);
  428.       if (b == '[' || b == 'O')
  429.            a = wgetch(window);
  430.       else
  431.            a = b;
  432.       
  433.       switch (a) {
  434.       case 'A': c = KEY_UP; break;
  435.       case 'B': c = KEY_DOWN; break;
  436.       case 'C': c = KEY_RIGHT; break;
  437.       case 'D': c = KEY_LEFT; break;
  438.       case '5':                       /* vt 300 prev. screen */
  439.            if (b == '[' && wgetch(window) == '~')
  440.             c = KEY_PPAGE;
  441.            break;
  442.       case '6':                       /* vt 300 next screen */
  443.            if (b == '[' && wgetch(window) == '~')
  444.             c = KEY_NPAGE;
  445.            break;
  446.       }
  447.      }
  448.      
  449.      /* The many forms of the return key... */
  450.      if ((c == KEY_ENTER)|| (c=='\r')) 
  451.       c = '\n'; /** SYSV curses Gack! **/
  452.      
  453.      /* The many forms of backspace */
  454.      if (c == '\010' || c == '\177' || c == KEY_BACKSPACE)
  455.       return('\b');
  456.  
  457.      return(c);
  458. }
  459.  
  460. int
  461. CURgetch(cur)
  462.   CursesObj *cur;
  463. {
  464.    return(CURwgetch(cur, stdscr));
  465. }  
  466.  
  467. /*
  468.  * Resets the screen when a size change has happened
  469.  */
  470.  
  471. void
  472. CURresize(cur)
  473.   CursesObj *cur;
  474. {
  475.      if (cur->inCurses) {
  476.       CURexit(cur);
  477.       CURsetScreen(cur, initscr());
  478.       CURenter(cur);
  479.      }
  480. }
  481.  
  482. /*
  483.  * Get one option displays a message, and gets a response
  484.  *
  485.  * If the Response has something in it, it is displayed and editable
  486.  * 
  487.  * If the user wants to abort, GetOneOption returns a -1, otherwise it
  488.  * returns a 0
  489.  */
  490.  
  491. int
  492. CURGetOneOption(cur, OptionName, Response)
  493.   CursesObj *cur;
  494.   char *OptionName, *Response;
  495. {
  496.      int i;
  497.      char *message[2];
  498.      char *response[2];
  499.  
  500.      message[0] = OptionName;
  501.      message[1] = NULL;
  502.      
  503.      response[0] = Response;
  504.      response[1] = NULL;
  505.  
  506.      i = CURRequest(cur, NULL, message, response);
  507.      
  508.      refresh();
  509.      return(i);
  510. }
  511.  
  512. /*
  513.  * This is the old version of GetOneOption, for those times when the
  514.  * garsh darn terminal is just too gadblam slow :-)
  515.  */
  516. int
  517. CUROldGetOneOption(cur, OptionName, Response)
  518.   CursesObj *cur;
  519.   char *OptionName, *Response;
  520. {
  521.      int i;
  522.      
  523.      mvaddstr(LINES-1, 0, OptionName);
  524.      standout();
  525.      addstr("    ");
  526.      standend();
  527.      clrtoeol();
  528.      move(LINES-1, strlen(OptionName));
  529.      
  530.      refresh();
  531.      echo();
  532.      i = CURwgetstr(cur, stdscr, Response, 4);
  533.      noecho();
  534.      
  535.      return(i);
  536. }
  537.  
  538.  
  539.  
  540. /*
  541.  * Fills in the Response with either a lowercase 'y' or 'n'
  542.  */
  543.  
  544. void
  545. CURgetYesorNo(cur, OptionName, Response)
  546.   CursesObj *cur;
  547.   char *OptionName, *Response;
  548. {
  549.      int c;
  550.      int posx, posy;
  551.  
  552.      mvaddstr(LINES-1, 0, OptionName);
  553.      clrtoeol();
  554.      noecho();
  555.      getyx(cur->Screen, posy, posx);
  556.      addch(' ');
  557.  
  558.      if (*Response == 'y')
  559.       mvaddstr(posy, posx+1, "y");
  560.      else {
  561.       *Response = 'n';
  562.       mvaddstr(posy, posx+1, "n ");
  563.      }
  564.      move(posy, posx+1);
  565.  
  566.      refresh();
  567.  
  568.      while (1) {
  569.       c = CURgetch(cur);
  570.  
  571.       if (c == 'y') {
  572.            mvaddstr(posy, posx+1, "Yes");
  573.            move(posy, posx+1);
  574.            refresh();
  575.            *Response = 'y';
  576.            *(Response +1) = '\0';
  577.            return;
  578.       }
  579.       else if (c == 'n') {
  580.            mvaddstr(posy, posx+1, "No ");
  581.            move(posy, posx+1);
  582.            refresh();
  583.            *Response = 'n';
  584.            *(Response +1) = '\0';
  585.            return;
  586.       }
  587.       
  588.       else if ((c == '\n')||(c=='\r')) {
  589.            return;
  590.       }
  591. #ifdef VMS
  592.       else if ( c == '\032' ) {    /* control-Z */
  593.         return;
  594.       }
  595. #endif
  596.       else {
  597.            CURBeep(cur);
  598.       }
  599.      }
  600. }
  601.       
  602. void 
  603. CURBeep(cur)
  604.   CursesObj *cur;
  605. {
  606. #ifdef SYSVCURSES
  607.      beep();
  608. #else
  609.      CURcenterline(cur,CURgetBell(cur),1);
  610.      /* tputs(CURgetBell(cur),1,CURoutchar); */
  611.      /* fflush(stdout); */
  612. #endif
  613. }
  614.  
  615.  
  616. void
  617. CURbox(cur, win, height,width)
  618.   CursesObj *cur;
  619.   WINDOW *win;
  620.   int width, height;
  621. {
  622.      int i;
  623.  
  624.      wmove(win,0,0);
  625. #ifdef SYSVCURSES
  626.      wattron(win, A_ALTCHARSET);
  627. #endif
  628.      waddch(win, BOX_UL);
  629.      for (i=0; i<width-2; i++)
  630.       waddch(win, BOX_HLINE);
  631.      waddch(win, BOX_UR);
  632.      for (i=1; i<height-1; i++) {
  633.       wmove(win, i,0);
  634.       waddch(win, BOX_VLINE);
  635.       wmove(win, i,width-1);
  636.       waddch(win, BOX_VLINE);
  637.      }
  638.  
  639.      wmove(win, height-1,0);
  640.      waddch(win, BOX_LL);
  641.      for (i=0; i<width-2; i++)
  642.       waddch(win, BOX_HLINE);
  643.      waddch(win, BOX_LR);
  644. #ifdef SYSVCURSES
  645.      wattroff(win, A_ALTCHARSET);
  646. #endif
  647. }
  648.  
  649.  
  650. void
  651. CURbutton(cur, win, Label, bright)
  652.   CursesObj *cur;
  653.   WINDOW *win;
  654.   char *Label;
  655.   boolean bright;
  656. {
  657. #ifdef SYSVCURSES
  658.      wattron(win, A_BOLD);
  659. #endif
  660.  
  661.      if (bright)
  662.       wstandout(win);
  663.  
  664.      waddstr(win, "[");
  665.      waddstr(win, Label);
  666.      waddstr(win, "]");
  667.  
  668.      if (bright)
  669.       wstandend(win);
  670. #ifdef SYSVCURSES
  671.      wattroff(win, A_BOLD);
  672. #endif
  673. }     
  674.  
  675. int
  676. CURDialog(cur, Wintitle, Message)
  677.   CursesObj *cur;
  678.   char **Message;
  679.   char *Wintitle;
  680. {
  681.      WINDOW *tempwin;
  682.      int i,messlength=25, winwidth;
  683.      int messheight=0;
  684.  
  685.      while (Message[messheight] != NULL) {
  686.       if (strlen(Message[messheight]) > messlength)
  687.           messlength = strlen(Message[messheight]);
  688.       messheight++;
  689.      }
  690.  
  691.      if (messlength > COLS)
  692.       messlength = COLS -4;
  693.      if (strlen(Wintitle) > messlength)
  694.       winwidth = strlen(Wintitle) + 2;
  695.      winwidth = messlength + 6;
  696.  
  697.      if (winwidth < 30)
  698.       winwidth = 30;
  699.      
  700.      tempwin = newwin(6+messheight, winwidth, (LINES-(6+messheight))/2, (COLS-winwidth) /2);
  701.      CURwenter(cur,tempwin);
  702.      CURbox(cur, tempwin, 6+messheight, winwidth);
  703.  
  704.      /** Add the message **/
  705.      for (i=0; i<messheight; i++) {
  706.           wmove(tempwin, 2+i,(winwidth - messlength)/2);
  707.           waddstr(tempwin, Message[i]);
  708.      }
  709.  
  710.  
  711.  
  712.      /** Add the window title **/
  713.      if (Wintitle != NULL) {
  714.       wmove(tempwin, 0,(winwidth - strlen(Wintitle))/2);
  715.       wstandout(tempwin);
  716.       waddstr(tempwin, Wintitle);
  717.       wstandend(tempwin);
  718.      }
  719.  
  720.      /** Add the keyboard labels **/
  721.      wmove(tempwin, 3+messheight, winwidth - 29);
  722.      CURbutton(cur, tempwin, "Cancel - ^G", FALSE);
  723.      waddch(tempwin, ' ');
  724.      CURbutton(cur, tempwin, "OK - Enter", FALSE);
  725.  
  726.      wrefresh(tempwin);
  727.  
  728.      switch(CURwgetch(cur, tempwin)) {
  729.      case -1:
  730.      case '\007':
  731.       delwin(tempwin);
  732.       return(-1);
  733.      default:
  734.       delwin(tempwin);
  735.       return(0);
  736.      }
  737. }
  738.  
  739.  
  740.  
  741. int
  742. CURRequest(cur,Wintitle,Prompts,Stowages)
  743.   CursesObj *cur;
  744.   char *Wintitle;
  745.   char **Prompts;
  746.   char **Stowages;
  747. {
  748.      WINDOW *tempwin;
  749.      int i,j;
  750.      int numprompts=0;
  751.      int maxpromptwidth =0;
  752.      int currentfield = 0;
  753.  
  754.      /** Find the number of prompts... and the max width***/
  755.      while (Prompts[numprompts++] != NULL)
  756.       if (strlen(Prompts[numprompts-1]) > maxpromptwidth)
  757.            maxpromptwidth = strlen(Prompts[numprompts-1]);
  758.      
  759.      numprompts --;
  760.  
  761.      if (numprompts == 0) {
  762.       return(-1);
  763.      }
  764.      
  765.      tempwin = newwin(6 + numprompts, COLS-2, (LINES-(6+numprompts))/2,1);
  766.      CURwenter(cur,tempwin);
  767.      CURbox(cur,tempwin, 6+numprompts, COLS-2);
  768.      
  769.      /*** Add the window title ***/
  770.      if (Wintitle != NULL) {
  771.       wmove(tempwin, 0,(COLS -2  - strlen(Wintitle))/2);
  772.       wstandout(tempwin);
  773.       waddstr(tempwin, Wintitle);
  774.       wstandend(tempwin);
  775.      }
  776.      
  777.      /** Add the prompts and typing area **/
  778.      for (i=0; i <numprompts; i++) {
  779.       wmove(tempwin, 2+i, 2);
  780.       waddstr(tempwin, Prompts[i]);
  781.       
  782.       /** Add the black space for the stowage, and the stowage, if it
  783.         exists **/
  784.       wmove(tempwin, 2+i, maxpromptwidth +4);
  785.       wstandout(tempwin);
  786.       waddstr(tempwin, Stowages[i]);
  787.       for (j=strlen(Stowages[i])+maxpromptwidth+4; j< COLS-6; j++) {
  788.            waddch(tempwin, ' ');
  789.       }
  790.       wstandend(tempwin);
  791.      }
  792.  
  793.      /** Add the labels **/
  794.      if (numprompts > 1) {
  795.       wmove(tempwin, 3+numprompts, 3);
  796.       CURbutton(cur, tempwin, "Switch Fields - TAB", FALSE);
  797.      }
  798.  
  799.      wmove(tempwin, 3+numprompts, COLS/2);
  800.      CURbutton(cur, tempwin, "Cancel ^G", FALSE);
  801.      waddch(tempwin, ' ');
  802.      CURbutton(cur, tempwin, "Accept - Enter", FALSE);
  803.  
  804.  
  805.      while (1) {
  806.       wmove(tempwin, 2+currentfield, maxpromptwidth +4);
  807.       wrefresh(tempwin);
  808.       switch (CURwgetstr(cur,tempwin,Stowages[currentfield],80)) {
  809.  
  810.       case '\t':
  811.       case KEY_DOWN:
  812.            /*** Move to another field ***/
  813.            currentfield = (currentfield +1) % numprompts;
  814.            break;
  815.  
  816.       case KEY_UP:
  817.            currentfield--;
  818.            if (currentfield <0)
  819.             currentfield = numprompts-1;
  820.            break;
  821.            
  822.       case '\007':
  823.       case -1:
  824.            /*** Cancel ***/
  825.            delwin(tempwin);
  826.            return(-1);
  827.            
  828.       case '\n':
  829.            delwin(tempwin);
  830.            return(0);
  831.       }
  832.       
  833.      }
  834.  
  835. }
  836.  
  837.  
  838. /* 
  839.  * CURChoice takes a bunch of titles, throws them on the screen,
  840.  * and asks the user to choose one.
  841.  *
  842.  * Returns the number chosen, or -1 if the user cancels.
  843.  */
  844.  
  845. int
  846. CURChoice(cur, Wintitle, choices, prompt)
  847.   CursesObj *cur;
  848.   char *Wintitle;
  849.   char **choices;
  850.   char *prompt;
  851. {
  852.      int numchoices=0, i, maxchoicewidth=0;
  853.      WINDOW *tempwin;
  854.      
  855.      while (choices[numchoices++] != NULL)
  856.       if ((i=strlen(choices[numchoices-1])) > maxchoicewidth)
  857.            maxchoicewidth = i;
  858.      
  859.      numchoices--;
  860.  
  861.      if (numchoices == 0)
  862.       return(-1);
  863.  
  864.      if ((i=strlen(prompt)) > maxchoicewidth)
  865.       maxchoicewidth = i;
  866.  
  867.      if ((i=strlen(Wintitle)) > maxchoicewidth)
  868.       maxchoicewidth = i;
  869.  
  870.  
  871.      tempwin = newwin(8+numchoices, maxchoicewidth + 10, (LINES-(6+numchoices))/2, (COLS-(maxchoicewidth+10))/2);
  872.      CURbox(cur, tempwin, 8+numchoices, 10 + maxchoicewidth);
  873.  
  874.      /*** Add the window title ***/
  875.      if (Wintitle != NULL) {
  876.       wmove(tempwin, 0,(maxchoicewidth+10 -2  - strlen(Wintitle))/2);
  877.       wstandout(tempwin);
  878.       waddstr(tempwin, Wintitle);
  879.       wstandend(tempwin);
  880.      }
  881.  
  882.      /*** Add the choices to the screen ***/
  883.  
  884.  
  885.      for (i=0; i<numchoices; i++) {
  886.       wmove(tempwin, 2+i,3);
  887.       wprintw(tempwin, "%d", i+1);
  888.       wprintw(tempwin, ". %s", choices[i]);
  889.       ;
  890.       
  891.      }
  892.  
  893.      /** Add the keystroke methods **/
  894.      wmove(tempwin, 5+numchoices, 3);
  895.      wprintw(tempwin, "[Cancel ^G]  [Choose 1-%d]", numchoices);
  896.  
  897.  
  898.      /** Add the prompt **/
  899.  
  900.      wmove(tempwin, 3+numchoices, 3);
  901.      wprintw(tempwin, "%s: ", prompt);
  902.  
  903.  
  904.      wrefresh(tempwin);
  905.  
  906.      while (1) {
  907.       i = CURwgetch(cur, tempwin);
  908.       wrefresh(tempwin);
  909.       if (i == '\007') {
  910.            delwin(tempwin);
  911.            return(-1);
  912.       }      
  913.  
  914.       if (i < '1' || i > ('0'+numchoices))
  915.            CURBeep(cur);
  916.       else {
  917.            delwin(tempwin);
  918.            return(i-'1');
  919.       }
  920.      }      
  921.  
  922. }
  923.  
  924. /********************** Cruft for VMS follows ****************************/
  925.  
  926. #ifdef VMS
  927. #include descrip
  928. #include iodef
  929. #include ssdef
  930. #include ttdef
  931. #include tt2def
  932.  
  933. static $DESCRIPTOR (term_name, "SYS$INPUT:");
  934. static $DESCRIPTOR (ctrlc_message, "{control-C}");
  935. struct char_buffer_type { unsigned short int dummy;
  936.               unsigned short int size;
  937.               unsigned long int tchars;
  938.               unsigned long int tchars2; } oldbuf, newbuf;
  939. short term_chan;
  940. static int first = 1;
  941. static int in_pos, in_len;
  942. static volatile int interrupt_flag;
  943. static long outband_mask[2] = { 0, 16 };
  944. static unsigned char buffer[20];
  945.  
  946. int CURinterrupt ( clear_flag )
  947.     int clear_flag;
  948. {
  949.     if ( interrupt_flag ) {
  950.     int temp = interrupt_flag;
  951.     if ( clear_flag ) interrupt_flag = 0;
  952.     return temp;
  953.     }
  954.     return 0;
  955. }
  956.  
  957. static int control_c_ast ( )
  958. {
  959.     int status;
  960.     short iosb[4];
  961.     interrupt_flag = 1;
  962.     status = sys$qiow ( 0, term_chan, IO$_SETMODE|IO$M_CTRLCAST, 
  963.     &iosb, 0, 0,
  964.     &control_c_ast, &outband_mask, 0, 0, 0, 0 );
  965. }
  966.  
  967. /*
  968.  * Define local replacement for wgetch that returns the characters without
  969.  * having to set the terminal /pasthru, which screws up control-Y processing.
  970.  */
  971. static int w_getch ( win )
  972.    int win;
  973. {
  974.    int status;
  975.    unsigned short iosb[4];
  976.    if ( in_pos < in_len ) { return (buffer[in_pos++]); }
  977.    status = sys$qiow ( 0, term_chan, IO$_READVBLK|IO$M_NOECHO|IO$M_NOFILTR,
  978.     &iosb, 0, 0, &buffer, 1, 0, 0, 0, 0 );
  979.    if ( (status&1) == 1 ) status = iosb[0];
  980.    if ( status == SS$_PARTESCAPE ) {
  981.     /* escape sequence in progress, fake a successful read */
  982.     status = 1;
  983.    }
  984.    if ( (status&1) != 1 ) exit ( status );
  985.    in_pos = 1;
  986.    in_len = iosb[1] + iosb[3];
  987.    return ( buffer[0] );
  988. }
  989. void
  990. setterm_pas()
  991. {
  992.   int status;
  993.   short iosb[4];
  994.   sys$assign(&term_name,&term_chan,0,0);
  995.  
  996.   if(first==1) sys$qiow(0,term_chan,IO$_SENSEMODE,0,0,0,&oldbuf,12,0,0,0,0);
  997.   first = 0;
  998.   newbuf = oldbuf;
  999.  
  1000.   /* set initial control-C AST on channel */
  1001.   in_pos = 0; in_len = 0;
  1002.    interrupt_flag = 0;
  1003.    status = sys$qiow ( 0, term_chan, IO$_SETMODE|IO$M_CTRLCAST, 
  1004.     &iosb, 0, 0,
  1005.     &control_c_ast, &outband_mask, 0, 0, 0, 0 );
  1006. }
  1007.  
  1008. void
  1009. resetterm()
  1010. {
  1011.   sys$qiow(0,term_chan,IO$_SETMODE,0,0,0,&oldbuf,12,0,0,0,0);
  1012.   sys$dassgn(term_chan);
  1013. }
  1014.  
  1015.  
  1016. /* VMS doesn't have termcap.  Unfortunately, the code in this */
  1017. /* module uses termcap just a little bit (it really shouldn't) */
  1018. /* rather than doing everything through curses */
  1019.  
  1020. /* The following simulates tputs, but does not support padding */
  1021. tputs(cp, affcnt, outc)
  1022.      register char *cp;
  1023.      int affcnt;
  1024.      int (*outc)();
  1025. {
  1026.       while (*cp)
  1027.         outc(*(cp++));
  1028. }
  1029. #endif /* VMS */
  1030.  
  1031.